package br.ufpe.cin.imlm2.jbeat.paths;

import static br.ufpe.cin.imlm2.util.FormattedIO.println;
import static br.ufpe.cin.imlm2.util.FormattedIO.printlnTabbed;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import br.ufpe.cin.imlm2.jbeat.model.LightWeightClass;
import br.ufpe.cin.imlm2.jbeat.model.LightWeightMethod;
import br.ufpe.cin.imlm2.jbeat.model.LightWeightScene;
import br.ufpe.cin.imlm2.jbeat.model.factory.DumpReadException;
import br.ufpe.cin.imlm2.jbeat.model.factory.DumpReader;
import br.ufpe.cin.imlm2.jbeat.paths.build.ForwardExceptionPathBuilder;
import br.ufpe.cin.imlm2.jbeat.paths.report.PathMetrics;
import br.ufpe.cin.imlm2.util.FormattedIO;
import br.ufpe.cin.imlm2.util.options.NoSuchOptionException;
import br.ufpe.cin.imlm2.util.options.ParsingException;

public class BuildPaths {

	/**
	 * @param args
	 * @throws ParsingException
	 * @throws IOException
	 * @throws FileNotFoundException
	 * @throws DumpReadException
	 * @throws NoSuchOptionException
	 */
	public static void main( String[] args ) throws ParsingException, FileNotFoundException,
			IOException, DumpReadException, NoSuchOptionException {
		PathOptions parser = new PathOptions();
		parser.setUsage( "USAGE:\n BUILDPATHS options" );
		List<String> unparsedArgs = parser.parse( args );
		if ( unparsedArgs.size() == 1 ) {
			String filePath = unparsedArgs.get( 0 );
			File file = new File( filePath );
			DumpReader reader = new DumpReader( new FileInputStream( file ) );
			LightWeightScene scene = reader.readDump();
			LightWeightMethod mainMethod = scene.getMain();
			for ( LightWeightClass c : mainMethod.getPropagatedMap().keySet() ) {
				ForwardExceptionPathBuilder builder;
				if ( parser.getMaxPathLength() != null )
					builder = new ForwardExceptionPathBuilder( c, mainMethod ,
							parser.getMaxPathLength(),null, true );
				else
					builder = new ForwardExceptionPathBuilder( c, mainMethod , null);
				System.err.println( "Starting path building for " + c + " at "
						+ mainMethod);
				Collection<ExceptionPath> paths = builder.buildEscapingExceptionPaths();
				System.err.println( "Path building for " + c + " completed." );

				Writer w;
				if ( parser.getOutpath().equals( "STDOUT" ) ) {
					w = new PrintWriter( System.out );
					printPaths( paths, w );
				} else {
					w = new PrintWriter( parser.getOutpath() );
					printPaths( paths, w );
					w.close();
				}

				System.gc();
				System.gc();
				System.gc();
			}
		} else {
			if ( !parser.isShowHelp() )
				System.out.println( "No input file. For help use --help argument." );
		}

	}

	private static void printPaths( Collection<ExceptionPath> paths, Writer w ) throws IOException {
		printlnTabbed( 0, "Number of paths " + paths.size(), w );
		ExceptionPath maxPath = PathMetrics.longestPath( paths );
		printlnTabbed( 0, "Length of the longest path : " + maxPath.length(), w );
		printlnTabbed( 0, "Average path length : " + PathMetrics.avgPathLength( paths ), w );
		int completed = PathMetrics.numberOfCompletePaths( paths );
		printlnTabbed( 0, "Complete/Incomplete paths : " + completed + "/"
				+ (paths.size() - completed), w );
		println( w );
		printlnTabbed( 0, "Longest path " + (maxPath.isComplete() ? "(complete)" : "(incomplete)")
				+ ":", w );
		printPath( maxPath, w );
		println( w );

	}

	/**
	 * @param p
	 * @param fw
	 * @throws IOException
	 */
	private static void printPath( ExceptionPath p, Writer fw ) throws IOException {
		Iterator<LightWeightMethod> itP = p.iterator();
		printlnTabbed( 0, "Starting path for " + p.getException() + " at " + p.getStartingPoint(),
				fw );
		itP.next();
		while ( itP.hasNext() ) {
			LightWeightMethod next = itP.next();
			if ( itP.hasNext() ) {
				FormattedIO.printlnTabbed( 1, next, fw );
			}
		}

		printlnTabbed( 0, "Ending path for " + p.getException() + " at " + p.getEndPoint(), fw );
	}

}
